
#include <BNode>
#include <BShape>
#include <BRender>
#include <BMouseEvent>
#include <BViewer>
#include <BPickItem>
#include <BGeometry>
#include <BMesh>
#include <BFont>
#include <BPainter>
#include <BImage>
#include <BCamera>
#include <BKeyEvent>
#include <BSystem>
#include <BCursor>
#include <BStyle>

#include "MyHandler.h"

MyHandler::MyHandler()
{
	_showNormals = false;
	_normalLengthRatio = 0.006f;
	_slideTimes = 0;
	_gridLinesVisible = true;
	_dirtyGridLines = true;
	_gridSize.set(100, 100);
	_gridSegment = 20;
	_gridColor.set(128, 128, 128);

	_target = 0;
	_leftPressed = false;
	_ctrlDown = false;
	_handleMode = HM_None;
	_handleAxis = HA_None;

	_cone_x = new BCone();
	_cone_x->setDepthTest(false);
	_cone_y = new BCone();
	_cone_y->setDepthTest(false);
	_cone_z = new BCone();
	_cone_z->setDepthTest(false);

	connect("target", &MyHandler::slotTargetChanged);
}
MyHandler::~MyHandler()
{

}

void MyHandler::setGridLineVisible(bool gridLineVisible)
{
	if (_gridLinesVisible != gridLineVisible)
	{
		_gridLinesVisible = gridLineVisible;
		_dirtyGridLines = true;;
		this->fresh();
	}
}
bool MyHandler::gridLineVisible() const
{
	return _gridLinesVisible;
}

void MyHandler::setGridSize(const BRealSize& gridSize)
{
	if (_gridSize != gridSize)
	{
		_gridSize = gridSize;
		_dirtyGridLines = true;
		this->fresh();
	}
}
const BRealSize& MyHandler::gridSize() const
{
	return _gridSize;
}

void MyHandler::setGridSegment(int gridSegment)
{
	if (_gridSegment != gridSegment)
	{
		_gridSegment = gridSegment;
		_dirtyGridLines = true;
		this->fresh();
	}
}
int MyHandler::gridSegment() const
{
	return _gridSegment;
}

void MyHandler::setGridColor(const BColor& color)
{
	if (_gridColor != color)
	{
		_gridColor = color;
		this->fresh();
	}
}
const BColor& MyHandler::gridColor() const
{
	return _gridColor;
}

void MyHandler::setShowNormals(bool showNormals)
{
	if (_showNormals != showNormals)
	{
		_showNormals = showNormals;
		this->fresh();
	}
}
bool MyHandler::showNormals() const
{
	return _showNormals;
}

void MyHandler::setNormalLengthRatio(float normalLengthRatio)
{
	if (_normalLengthRatio != normalLengthRatio)
	{
		_normalLengthRatio = normalLengthRatio;
		this->fresh();
	}
}
float MyHandler::normalLengthRatio() const
{
	return _normalLengthRatio;
}

void MyHandler::drawNormals(BShape* shape, BRender& render)
{
	if (_showNormals == false)
		return;
	render.setLighting(false);
	render.setColor(255, 0, 0);
	if (BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
	{
		BReal nlen = geometry->space().radius() * _normalLengthRatio * 0.1f;
		BVectorArray* vertices = geometry->vertices();
		BVectorArray* normals = geometry->normals();
		for (int vi = 0; vi < vertices->size(); vi++)
		{
			const BVector& v = vertices->at(vi);
			const BVector& n = normals->at(vi);
			render.drawLine(v, v + n * nlen);
		}
		return;
	}
	if (BMesh* mesh = dynamic_cast<BMesh*>(shape))
	{
		BReal nlen = mesh->space().radius() * _normalLengthRatio * 0.1f;
		BVectorArray* vertices = mesh->vertices();
		BVectorArray* normals = mesh->normals();
		for (int vi = 0; vi < vertices->size(); vi++)
		{
			const BVector& v = vertices->at(vi);
			const BVector& n = normals->at(vi);
			render.drawLine(v, v + n * nlen);
		}
		return;
	}
}
void MyHandler::freshFrustum()
{
	BCamera* camera = this->camera();
	BReal near = camera->near();
	BReal far = camera->far();

	_frustum.near_v0 = this->viewer()->vertex(_selectRect.leftTop(), near);
	_frustum.near_v1 = this->viewer()->vertex(_selectRect.leftBottom(), near);
	_frustum.near_v2 = this->viewer()->vertex(_selectRect.rightBottom(), near);
	_frustum.near_v3 = this->viewer()->vertex(_selectRect.rightTop(), near);

	_frustum.far_v0 = this->viewer()->vertex(_selectRect.leftTop(), far);
	_frustum.far_v1 = this->viewer()->vertex(_selectRect.leftBottom(), far);
	_frustum.far_v2 = this->viewer()->vertex(_selectRect.rightBottom(), far);
	_frustum.far_v3 = this->viewer()->vertex(_selectRect.rightTop(), far);

	_frustum.freshPlanes();

}
void MyHandler::frustumPick()
{
	BArray<BPickItemHolder> itemsPicked;
	BScene* scene = this->scene();
	for (int i = 0; i < scene->shapeCount(); i++)
	{
		BShape* shape = scene->shape(i);
		if (_frustum.clip(shape->space()))
			continue;
		BPickItem* item = new BPickItem();
		item->setShape(shape);
		itemsPicked.append(item);
	}
	for (int i = 0; i < scene->nodeCount(); i++)
	{
		BNode* node = scene->node(i);
		if (_frustum.clip(node->space()))
			continue;
		BMatrix inverMatrix = node->matrix();
		inverMatrix.inverse();
		Frustum localFrustum = _frustum * inverMatrix;
		for (int s = 0; s < node->shapeCount(); s++)
		{
			BShape* shape = node->shape(s);
			if (localFrustum.clip(shape->space()))
				continue;
			BPickItem* item = new BPickItem();
			item->setNode(node);
			item->setShape(shape);
			itemsPicked.append(item);
		}
	}
}

void MyHandler::updateAxis()
{
	updateMoveAxis();
	updateRotateAxis();
	updateScaleAxis();
}
void MyHandler::updateMoveAxis()
{
	BVector center = _target->space().center();

	_axis_x.set(center, center + BVector(_axisSize, 0, 0));
	_axis_y.set(center, center + BVector(0, _axisSize, 0));
	_axis_z.set(center, center + BVector(0, 0, _axisSize));

	BReal coneSize = _axisSize * 0.1;
	_cone_x->setRadius(coneSize / 2);
	_cone_x->setHeight(coneSize);
	_cone_x->setPosition(_axis_x.end());
	_cone_x->setRotate(BQuater(BVector(0, 0, 1), BVector(1, 0, 0)));

	_cone_y->setRadius(coneSize / 2);
	_cone_y->setHeight(coneSize);
	_cone_y->setPosition(_axis_y.end());
	_cone_y->setRotate(BQuater(BVector(0, 0, 1), BVector(0, 1, 0)));

	_cone_z->setRadius(coneSize / 2);
	_cone_z->setHeight(coneSize);
	_cone_z->setPosition(_axis_z.end());

	BReal quadSize = _axisSize / 3.0;
	_quad_xy.a() = center;
	_quad_xy.b() = center + BVector(quadSize, 0, 0);
	_quad_xy.c() = center + BVector(quadSize, quadSize, 0);
	_quad_xy.d() = center + BVector(0, quadSize, 0);

	_quad_yz.a() = center;
	_quad_yz.b() = center + BVector(0, quadSize, 0);
	_quad_yz.c() = center + BVector(0, quadSize, quadSize);
	_quad_yz.d() = center + BVector(0, 0, quadSize);

	_quad_xz.a() = center;
	_quad_xz.b() = center + BVector(quadSize, 0, 0);
	_quad_xz.c() = center + BVector(quadSize, 0, quadSize);
	_quad_xz.d() = center + BVector(0, 0, quadSize);

}
void MyHandler::updateRotateAxis()
{
	BReal unit = 2 * PIf / 24;

	for (int i = 0; i < 24; i++)
	{
		BReal x = cos(i * unit) * _axisSize;
		BReal y = sin(i * unit) * _axisSize;
		_rotateCircleXY[i] = BVector(x, y, 0);
	}

	for (int i = 0; i < 24; i++)
	{
		BReal y = cos(i * unit) * _axisSize;
		BReal z = sin(i * unit) * _axisSize;
		_rotateCircleYZ[i] = BVector(0, y, z);
	}

	for (int i = 0; i < 24; i++)
	{
		BReal x = cos(i * unit) * _axisSize;
		BReal z = sin(i * unit) * _axisSize;
		_rotateCircleXZ[i] = BVector(x, 0, z);
	}

	_rotateSphere->setRadius(_axisSize * 0.96);
}
void MyHandler::updateScaleAxis()
{

}

bool MyHandler::pickAxis(const BLine& line)
{
	BScene* scene = this->viewer()->scene();
	if (_target)
	{
		switch (_handleMode)
		{
		case HM_Move:
			return pickMoveAxis(line);
		case HM_Rotate:
			return pickRotateAxis(line);
		case HM_Scale:
			return pickScaleAxis(line);
		default:
			return false;
		}
	}
	return false;
}
bool MyHandler::pickMoveAxis(const BLine& line)
{
	BVector pos = _target->space().center();

	HandleAxis axis = HA_None;
	float ratio = 1;
	float ratio_xy = 0;
	if (line.intersect(_quad_xy, ratio_xy) && ratio_xy < ratio)
	{
		axis = HA_XY;
		ratio = ratio_xy;
	}
	float ratio_yz = 0;
	if (line.intersect(_quad_yz, ratio_yz) && ratio_yz < ratio)
	{
		axis = HA_YZ;
		ratio = ratio_yz;
	}
	float ratio_xz = 0;
	if (line.intersect(_quad_xz, ratio_xz) && ratio_xz < ratio)
	{
		axis = HA_XZ;
	}
	if (axis)
	{
		_handleAxis = axis;
		this->viewer()->fresh();
	}
	else
	{
		BReal disX = line.distance(_axis_x);
		BReal disY = line.distance(_axis_y);
		BReal disZ = line.distance(_axis_z);
		BReal pickRange = _axisSize / 20;
		if (disX < pickRange)
			axis = HA_X;
		if (disY < pickRange)
			axis = HA_Y;
		if (disZ < pickRange)
			axis = HA_Z;
		_handleAxis = axis;
		this->viewer()->fresh();
	}
	return _handleAxis != HA_None;
}
bool MyHandler::pickRotateAxis(const BLine& line)
{
	HandleAxis axis = HA_None;

	BQuater quat = _matrix.rotate();
	BVector center = _matrix.position();

	BVector perp = line.perpVertex(center);
	BReal dist = (perp - center).length();
	if (dist < _axisSize)
	{
		BReal len = sqrt(_axisSize * _axisSize - dist * dist);
		BVector point = perp - line.direct() * len;

		BReal range = this->viewer()->unit(center) * 10;
		BVector axis_z = quat * BVector(0, 0, 1);
		BVector axis_y = quat * BVector(0, 1, 0);
		BVector axis_x = quat * BVector(1, 0, 0);

		BPlane plane_xy(axis_z, center);
		BReal dist_xy = abs(plane_xy.dist(point));

		BPlane plane_yz(axis_x, center);
		BReal dist_yz = abs(plane_yz.dist(point));

		BPlane plane_xz(axis_y, center);
		BReal dist_xz = abs(plane_xz.dist(point));

		if (dist_xy < range && dist_xy < dist_yz && dist_xy < dist_xz)
			axis = HA_XY;
		else if (dist_yz < range && dist_yz < dist_xy && dist_yz < dist_xz)
			axis = HA_YZ;
		else if (dist_xz < range && dist_xz < dist_xy && dist_xz < dist_yz)
			axis = HA_XZ;
	}
	if (_handleAxis != axis)
	{
		_handleAxis = axis;
		this->viewer()->fresh();
	}
	return _handleAxis;
}
bool MyHandler::pickScaleAxis(const BLine& line)
{
	return false;
}

void MyHandler::applyOpera(const BLine& line)
{
	if (!_target || !_transOpera)
		return;
	if (_handleMode == HM_Move)
		applyMoveOpera(line);
	if (_handleMode == HM_Rotate)
		applyRotateOpera(line);
	if (_handleMode == HM_Scale)
		applyScaleOpera(line);
	_dirtyAxis = true;
	this->fresh();
}
void MyHandler::applyMoveOpera(const BLine& line)
{
	BMatrix matrix = _transOpera->origin();
	BVector pos = matrix.position();
	BVector begin, end;
	switch (_handleAxis)
	{
	case HA_X:
		begin = _linePressed.closestVertex(_axis_x);
		end = line.closestVertex(_axis_x);
		break;
	case HA_Y:
		begin = _linePressed.closestVertex(_axis_y);
		end = line.closestVertex(_axis_y);
		break;
	case HA_Z:
		begin = _linePressed.closestVertex(_axis_z);
		end = line.closestVertex(_axis_z);
		break;
	case HA_XY:
	{
		BPlane plane(_quad_xy.normal(), pos);
		_linePressed.intersect(plane, begin);
		line.intersect(plane, end);
		break;
	}
	case HA_YZ:
	{
		BPlane plane(_quad_yz.normal(), pos);
		_linePressed.intersect(plane, begin);
		line.intersect(plane, end);
		break;
	}
	case HA_XZ:
	{
		BPlane plane(_quad_xz.normal(), pos);
		_linePressed.intersect(plane, begin);
		line.intersect(plane, end);
		break;
	}
	default:
		return;
	}
	BVector offset = end - begin;
	BVector newPos = pos + offset;
	matrix.setPosition(newPos);
	_transOpera->setMatrix(matrix);
	_transOpera->redo();
	this->viewer()->fresh();
}
void MyHandler::applyRotateOpera(const BLine& line)
{
	BVector center = _matrix.position();
	BQuater rotate = _matrix.rotate();
	BVector begin, end;

	switch (_handleAxis)
	{
	case HA_XY:
	{
		BVector axis = rotate * BVector(0, 0, 1);
		BPlane plane_xy(axis, center);
		_linePressed.intersect(plane_xy, begin);
		line.intersect(plane_xy, end);

		begin -= center;
		end -= center;
		begin.normalize();
		end.normalize();

		BReal angle = begin.angle(end);
		BVector normal = begin.cross(end);
		if (normal.dot(axis) < 0.0f)
			angle = -angle;

		BMatrix matrix = _transOpera->origin();
		BVector euler = matrix.eulerAngle();
		euler.z() += angle;
		matrix.setEulerAngle(euler);
		_transOpera->setMatrix(matrix);
		this->viewer()->fresh();
		break;
	}
	case  HA_YZ:
	{
		BVector axis = rotate * BVector(1, 0, 0);
		BPlane plane_yz(axis, center);
		_linePressed.intersect(plane_yz, begin);
		line.intersect(plane_yz, end);

		begin -= center;
		end -= center;
		begin.normalize();
		end.normalize();

		BReal angle = begin.angle(end);
		BVector normal = begin.cross(end);
		if (normal.dot(axis) < 0.0f)
			angle = -angle;

		BMatrix matrix = _transOpera->origin();
		BVector euler = matrix.eulerAngle();
		euler.x() += angle;
		matrix.setEulerAngle(euler);
		_transOpera->setMatrix(matrix);
		this->viewer()->fresh();
		break;
	}
	case HA_XZ:
	{
		BVector axis = rotate * BVector(0, 1, 0);
		BPlane plane_xz(axis, center);
		_linePressed.intersect(plane_xz, begin);
		line.intersect(plane_xz, end);

		begin -= center;
		end -= center;
		begin.normalize();
		end.normalize();

		BReal angle = begin.angle(end);
		BVector normal = begin.cross(end);
		if (normal.dot(axis) < 0.0f)
			angle = -angle;

		BMatrix matrix = _transOpera->origin();
		BVector euler = matrix.eulerAngle();
		euler.y() += angle;
		matrix.setEulerAngle(euler);
		_transOpera->setMatrix(matrix);
		this->viewer()->fresh();
		break;
	}
	default:
		break;
	}

}
void MyHandler::applyScaleOpera(const BLine& line)
{

}

void MyHandler::drawAxis(BRender& render)
{
	switch (_handleMode)
	{
	case HM_Move:
		drawMoveAxis(render);
		break;
	case HM_Rotate:
		drawRotateAxis(render);
		break;
	case HM_Scale:
		drawScaleAxis(render);
		break;
	default:
		break;
	}
}
void MyHandler::drawMoveAxis(BRender& render)
{
	render.setCullback(false);
	render.setDepthTest(false);

	BReal side = _axisSize * 0.1;
	if (_handleAxis & HA_X)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(255, 0, 0, 255);
	render.drawLine(_axis_x);
	_cone_x->setColor(render.color());
	render.drawShape(_cone_x);

	if (_handleAxis & HA_Y)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 255, 0, 255);
	render.drawLine(_axis_y);
	_cone_y->setColor(render.color());
	render.drawShape(_cone_y);

	if (_handleAxis & HA_Z)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 0, 255, 255);
	render.drawLine(_axis_z);
	_cone_z->setColor(render.color());
	render.drawShape(_cone_z);

	if (_handleAxis == HA_XY)
		render.setColor(255, 255, 0, 200);
	else
		render.setColor(255, 255, 0, 76);
	render.fillQuad(_quad_xy);

	if (_handleAxis == HA_YZ)
		render.setColor(255, 255, 0, 200);
	else
		render.setColor(0, 255, 255, 76);
	render.fillQuad(_quad_yz);

	if (_handleAxis == HA_XZ)
		render.setColor(255, 255, 0, 200);
	else
		render.setColor(255, 0, 255, 76);
	render.fillQuad(_quad_xz);
}
void MyHandler::drawRotateAxis(BRender& render)
{
	render.setMatrix(_basicMatrix);
	render.setLighting(false);
	render.setDepthTest(true);
	//glDepthFunc(GL_ALWAYS);

	if (_handleAxis == HA_XY)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(255, 0, 0, 255);
	render.drawLineLoop(_rotateCircleXY);

	if (_handleAxis == HA_YZ)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 255, 0, 255);
	render.drawLineLoop(_rotateCircleYZ);

	if (_handleAxis == HA_XZ)
		render.setColor(255, 255, 0, 255);
	else
		render.setColor(0, 0, 255, 255);
	render.drawLineLoop(_rotateCircleXZ);

	render.setLighting(true);
	render.setDepthTest(true);
	//glDepthFunc(GL_LESS);

	if (_handleAxis)
		_rotateSphere->setColor(255, 255, 0, 200);
	else
		_rotateSphere->setColor(128, 128, 128, 200);
	render.drawShape(_rotateSphere);
}
void MyHandler::drawScaleAxis(BRender& render)
{

}

void MyHandler::slotTargetChanged(BObject* object, const BValue& value)
{
	_target = (Target*)value;
	this->fresh();
}

void MyHandler::attached(BViewer* viewer)
{
	BScene* scene = viewer->scene();
}
void MyHandler::detached(BViewer* viewer)
{

}

void MyHandler::paint(BPainter& painter)
{
	BRect crect = this->viewer()->centerRect();
	if (_leftPressed)
	{
		painter.setColor(234, 234, 234);
		painter.drawRect(_selectRect);
	}

	BSize imageSize(200, 136);
	BRect imageRect = crect.align(Align_RightBottom, imageSize);
	painter.setColor(128, 128, 128, 128);
	painter.fillRoundRect(imageRect, 16);
	painter.bind(this->camera());
	painter.fillRoundRect(imageRect, 16);
	painter.unbind();

}
void MyHandler::render(BRender& render)
{
	if (_gridLinesVisible)
	{
		render.setLighting(false);
		render.setLineWidth(2);
		render.setLineSmooth(true);
		render.setColor(_gridColor);
		render.drawLines(_horLines);
		render.drawLines(_verLines);
	}
	//render.setColor(255, 0, 0, 200);
	//render.fillQuad(_frustum.near_v0, _frustum.near_v1, _frustum.near_v2, _frustum.near_v3);
	//render.fillQuad(_frustum.far_v0, _frustum.far_v1, _frustum.far_v2, _frustum.far_v3);
	//render.setColor(255, 255, 0, 200);
	//render.fillQuad(_frustum.near_v0, _frustum.near_v1, _frustum.far_v1, _frustum.far_v0);
	//render.fillQuad(_frustum.near_v2, _frustum.near_v3, _frustum.far_v3, _frustum.far_v2);
	if (_target)
	{
		render.setLighting(false);
		render.setLineWidth(2);
		render.setLineSmooth(true);
		if (BShape* shape = _target->shape())
		{
			BBox box = shape->box() * shape->matrix();
			if (BNode* node = _target->node())
			{
				box *= node->matrix();
			}
			drawNormals(shape, render);
			render.setColor(200, 200, 0);
			render.drawBox(box);
		}
		if (BNode* node = _target->node())
		{
			BBox box = node->box() * node->matrix();
			for (int i = 0; i < node->shapeCount(); i++)
			{
				BShape* shape = node->shape(i);
				drawNormals(shape, render);
			}
			render.setColor(200, 200, 200);
			render.drawBox(box);
		}
		if (BGroup* group = _target->group())
		{
			BSpace space = group->space();
			for (int i = 0; i < group->shapeCount(); i++)
			{
				BShape* shape = group->shape(i);
				drawNormals(shape, render);
			}
			render.setLineStipple(0xF0F0);
			render.setColor(0, 200, 200);
			render.drawSpace(space);
			render.setLineStipple(0);
		}
	}
}

void MyHandler::updateEvent(const BEvent& event)
{
	if (_slideTimes > 0)
	{
		BVector position = this->camera()->position();
		BVector center = this->camera()->center();
		BVector up = this->camera()->up();

		position += (_slidePosition - position) / _slideTimes;
		center += (_slideCenter - center) / _slideTimes;
		up += (_slideUp - up) / _slideTimes;
		up.normalize();

		this->camera()->setPosition(position);
		this->camera()->setCenter(center);
		this->camera()->setUp(up);
		BReal dist = (position - center).length();
		if (this->camera()->far() < dist * 2)
			this->camera()->setFar(dist * 2);
		_slideTimes--;
	}
}
void MyHandler::styleEvent(const BEvent& event)
{
	if (const BStyle* style = event.value())
	{
		if (BImage* image = style->image("cursor-add"))
		{
			BCursor* cursor_add = new BCursor(image);
			this->setProperty("cursor-add", cursor_add);
		}
	}
}
void MyHandler::freshEvent(const BEvent& event)
{
	if (_dirtyGridLines)
	{
		BReal minx = -_gridSize.width() / 2;
		BReal maxx = _gridSize.width() / 2;
		BReal miny = -_gridSize.height() / 2;
		BReal maxy = _gridSize.height() / 2;
		BReal sx = _gridSize.width() / _gridSegment;
		BReal sy = _gridSize.height() / _gridSegment;
		_verLines.resize(_gridSegment + 1);
		for (int i = 0; i < _verLines.size(); i++)
		{
			BReal x = minx + sx * i;
			_verLines[i].set(x, miny, 0, x, maxy, 0);
		}
		_horLines.resize(_gridSegment + 1);
		for (int i = 0; i < _horLines.size(); i++)
		{
			BReal y = miny + sy * i;
			_horLines[i].set(minx, y, 0, maxx, y, 0);
		}
		_dirtyGridLines = false;
	}
}

bool MyHandler::keyDownEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_Space)
	{
		BSpace space;
		if (_target)
			space = _target->space();
		if (space.empty())
			space = this->scene()->space();
		if (space.empty())
		{
			BReal minx = -_gridSize.width() / 2;
			BReal maxx = _gridSize.width() / 2;
			BReal miny = -_gridSize.height() / 2;
			BReal maxy = _gridSize.height() / 2;
			BReal hh = bMin(_gridSize.width(), _gridSize.height()) / 2;
			space.reset(minx, miny, -hh, maxx, maxy, hh);
		}
		if (space.valid())
		{
			BVector center = space.center();
			BVector direct(0, 1, 1);
			if (this->camera()->position() != center)
				direct = this->camera()->position() - center;
			direct.normalize();
			_slidePosition = center + direct * space.radius() * 3;
			_slideCenter = center;
			_slideUp.set(0, 0, 1);
			_slideTimes = 10;
		}
		return true;
	}
	if (keyEvent.key() == Key_LCtrl)
	{
		_ctrlDown = true;
		if (BCursor* cursor_add = this->property("cursor-add"))
			this->viewer()->setCursor(cursor_add);
		return true;
	}
	if (keyEvent.key() == Key_Delete)
	{
		emit("delete", _target);
		_target = 0;
		this->fresh();
	}
	return false;
}
bool MyHandler::keyUpEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_LCtrl)
	{
		_ctrlDown = false;
		this->viewer()->setCursor(0);
		return true;
	}
	return false;
}

bool MyHandler::mousePressEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		_leftPressed = true;
		_pressedPoint = mouseEvent.pos();
		_selectRect.reset(_pressedPoint);
		this->fresh();
		return true;
	}
	return BSphereHandler::mousePressEvent(mouseEvent);
}
bool MyHandler::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		_leftPressed = false;
		this->fresh();
	}
	return BSphereHandler::mouseReleaseEvent(mouseEvent);
}
bool MyHandler::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_None)
	{
		const BPoint& pos = mouseEvent.pos();
		BPickItem* item = this->viewer()->pick(pos);
		bool equal = !_hoveredItem && !item;
		if(!equal)
			equal = _hoveredItem && item && _hoveredItem->node() == item->node() && _hoveredItem->shape() == item->shape();
		if (!equal)
		{
			_hoveredItem = item;
			this->fresh();
			return true;
		}
	}
	if (mouseEvent.button() == Button_Left)
	{
		const BPoint& pos = mouseEvent.pos();
		_selectRect.reset(_pressedPoint);
		_selectRect.expand(pos);
		freshFrustum();
		frustumPick();
		bool ctrlPressed = BSystem::KeyState(Key_LCtrl);
		BScene* scene = this->viewer()->scene();
		Target* target = new Target(scene);
		if (ctrlPressed)
		{
			if (target->matchPickItem(_hoveredItem))
			{
				target->removeShape(_hoveredItem->shape());
				target->removeNode(_hoveredItem->node());
				target->removeGroup(_hoveredItem->group());
			}
			else
			{
				target->insertShape(_hoveredItem->shape());
				target->insertNode(_hoveredItem->node());
				target->insertGroup(_hoveredItem->group());
			}
		}
		else
		{
			target->clear();
			if (_hoveredItem)
			{
				target->insertShape(_hoveredItem->shape());
				target->insertNode(_hoveredItem->node());
				target->insertGroup(_hoveredItem->group());
			}
		}
		if (!BSystem::KeyState(Key_LShift))
			target->clearShapes();
		this->emit("target-changed", target);
		this->fresh();
	}
	return BSphereHandler::mouseMoveEvent(mouseEvent);
}
bool MyHandler::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (_ctrlDown)
		{
			BPoint pos = mouseEvent.pos();
			if (const BPickItem* item = this->viewer()->pick(pos))
			{
				_focusPoint = item->absolutePoint();
				BVector vec = _focusPoint - this->camera()->position();
				BVector direct = this->camera()->center() - this->camera()->position();
				direct.normalize();
				BReal distance = direct.dot(vec);
				BVector center = this->camera()->position() + direct * distance;
				this->camera()->setCenter(center);
			}
		}
		if (_hoveredItem)
		{
			if (_target == 0)
				_target = new Target(this->scene());
			else
				_target->clear();
			_target->insertNode(_hoveredItem->node());
			_target->insertShape(_hoveredItem->shape());
		}
		else
		{
			if (_target)
				_target = 0;
		}
		emit("target", _target);
		this->fresh();
		return true;
	}
	return BSphereHandler::mouseClickEvent(mouseEvent);
}

